/*! \file textline.cpp
	
	This contains the implementation of the TextLine class
*/

#include "textline.h"
#include "image.h"
#include "container.h"

TextLine::TextLine( Component* parent ) :
	TextComponent( parent )
	{
		addListener( this );
	}
	
void TextLine::draw() {
	
	int screenX = getScreenX(), screenY = getScreenY();
	GUI* gui = GUI::getInstance();
	gui->drawRectangle( screenX, screenY, w, h, bgColorTop, bgColorBottom );
	
	glColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
	glEnable(GL_TEXTURE_2D);
	Font* font = GUI::getInstance()->getFont();
	
	int visibleWidth = 0;
	int i;
	int start = scroll;
	//~ if ( scroll > 0 ) start = scroll - 1;
	for ( i = start; i < buffer.length(); i ++ ) {
		visibleWidth += font->letters[(int)buffer[i]].advancex;
		if ( visibleWidth > widthWithoutBorder ) {
			break;
		}
	}
	string visibleString = buffer.substr( start, i - start );
	//~ cout << visibleString << endl;
	
	//~ GUI::setClippingArea( screenX + borderWidth, screenY, widthWithoutBorder, h );
	
	font->writeString( visibleString, borderWidth, h - font->getMaxAdvanceY() / 2 );	
	
	//~ GUI::removeClippingArea();
	
	// Draw the cursor if this is the component with the focus
	if ( this == ((Container*)parent)->getFocus() && parent == gui->getFocusedComponent() ) {
		int cPos = font->widthOfString( buffer.substr( scroll, cursor - scroll ) );
		cPos += borderWidth;
		gui->drawRectangle( screenX + cPos, screenY, 2, h, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f );
	}
	
	if ( border ) {
		ImageHandler::getInstance()->guiBorder( sideID1, cornerID1, screenX, screenY, w, h );
	}
	
}

int TextLine::ctrlRight() {
	Font* font = GUI::getInstance()->getFont();
	int leftPosition = cursor;
	int pixels = 0;
	// Find the first special character starting from the cursor going to the right
	int rightPosition = buffer.find_first_of( " ()", leftPosition );
	// Now, start from that first special character and find the first NON-special character
	rightPosition = buffer.find_first_not_of( " ()", rightPosition ); // -1 if it didn't find anything
	
	// If that didn't work, then just continue to the end of the string
	if ( rightPosition == -1 ) { 
		rightPosition = buffer.length();
	}
	
	for ( int i = cursor; i < rightPosition; i ++ ) {
		pixels += font->letters[buffer[i]].advancex;
	}
	cursor = rightPosition;
	return pixels;
}	

int TextLine::ctrlLeft() {
	Font* font = GUI::getInstance()->getFont();
	
	int rightPosition = cursor; 
	int leftPosition = 0;
	int pixels = 0;
	
	// See what the character before the cursor is
	char c = buffer.at( cursor - 1 );
	
	// If it's one of these special characters, then we'll jump over all of them (from right to left) until we find the 
	// rightmost non-special character
	if ( c == ' ' || c == '(' || c == ')' ) {
		rightPosition = buffer.find_last_not_of( " ()", cursor - 1 ); // -1 if it didn't find anything
	}
	
	// Now, move the leftPosition to the beginning of the non-special characters
	// This is guaranteed to at least be 0, because the return value of find_last_of
	// is >= -1, and we're adding 1 to it
	if ( rightPosition > 0 ) {
		leftPosition = buffer.find_last_of( " ()", rightPosition - 1 ) + 1;
	}
	
	for ( int i = leftPosition; i < cursor; i ++ ) {
		pixels += font->letters[buffer[i]].advancex;
	}
	cursor = leftPosition;
	return pixels;
}

void TextLine::performAction() {
	cout << "TextLine::Action performed" << endl;
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		(*j)->actionPerformed( Event( this ) );
	}
}

void TextLine::resetBuffer() {
	buffer = "";
	scroll = 0;
	cursor = 0;
	widthInPixels = 0;
	totalWidth = 0;
}

void TextLine::keyDown(Event e) {
	GUI* gui = GUI::getInstance();
	// Get the font to use for checking the width of characters (it is not used here to draw)
	Font* font = gui->getFont();
	//~ cout << e.button << " " << (char)e.button << endl;

	// 'pos' is used in one of the 'if' statements as just a temporary variable
	int pos;
	// There are a bunch of ways to add a character...
	// either by pressing space, a letter, or a symbol (or shift+symbol like '?').
	// Since there are some common things to do whenever you add a character, we just keep
	// these two pieces of information about the action, then do the common functions after
	bool addedAChar = false;
	char added = ' ';
	
	// Pressing a key
	if ( e.button >= 'A' && e.button <= 'Z' ) {
		// Keys are taken in as capital letters, so we need to
		// subtract if shift isn't being held
		if ( !gui->shiftHeld() ) {
			e.button += 'a' - 'A';
		}
		added = e.button;
		addedAChar = true;
	} else if ( e.button == GLFW_KEY_ENTER ) {
		//process( buffer );
		performAction();
		cout << buffer << endl;
		//~ buffer = "";
		//~ scroll = 0;
		//~ cursor = 0;
		//~ widthInPixels = 0;
		//~ totalWidth = 0;
	} else if ( e.button == GLFW_KEY_SPACE ) { // space
		added = ' ';
		addedAChar = true;
	} else if ( e.button == GLFW_KEY_BACKSPACE ) { // backspace
		if ( buffer.length() > 0 ) {
			if ( gui->ctrlHeld() ) {
				// ctrlLeft will change cursor, so we store the old position
				int oldCursor = cursor;
				// Move the cursor to where it will end up after removing the previous word
				int pixels = ctrlLeft();
				// Readjust our width values
				widthInPixels -= pixels;
				totalWidth -= pixels;
				// Cut out the word from the string
				buffer = buffer.substr( 0, cursor ) + buffer.substr( oldCursor );
			} else {
				// The amount of pixels we remove is equal to the size of the letter before the cursor
				int pixels = font->letters[buffer[cursor - 1]].advancex;
				// Readjust the width values
				widthInPixels -= pixels;
				totalWidth -= pixels;
				// Cut out the letter from the string
				buffer = buffer.substr( 0, cursor - 1 ) + buffer.substr( cursor );
				// Readjust the cursor
				cursor--;
			}
		}
	} else if ( ( pos = TextComponent::symbols.find( (char)e.button, 0 ) ) != string::npos ) {
		// If you're typing a special symbol like '1' or '[', check to see if shift is held down
		if ( !gui->shiftHeld() ) {
			// If it isn't, then just add the character
			added = TextComponent::symbols[pos];
			addedAChar = true;
		} else {
			// If it is, then change the character to '!' or '{' (etc.)
			added = TextComponent::shiftSymbols[pos];
			addedAChar = true;
		}
	} else if ( e.button == GLFW_KEY_LEFT && cursor > 0 ) { // left
		if ( gui->ctrlHeld() ) {
			// Ctrl+left: adjust the cursor position and figure out how many pixels over it moved
			int pixels = ctrlLeft();
			// We don't change totalWidth here because we didn't modify the string
			widthInPixels -= pixels;
		} else {
			// Just pressing left... slide over one character and adjust the
			// width appropriately
			int pixels = font->letters[buffer[cursor - 1]].advancex;
			widthInPixels -= pixels;
			cursor--;
		}
	} else if ( e.button == GLFW_KEY_RIGHT ) {
		if ( gui->ctrlHeld() ) {
			// Ctrl+right: see ctrl+left
			int pixels = ctrlRight();
			widthInPixels += pixels;
		} else {
			int pixels = font->letters[buffer[cursor]].advancex;
			widthInPixels += pixels;
			cursor++;
		}
	}
	
	// These are the common things to do when adding a character
	if ( addedAChar ) {
		// This is my stupid method of putting a character in a string
		char addThis[2] = {0};
		addThis[0] = added;
		buffer.insert( cursor, &addThis[0] );
		// You typed something, so move the cursor
		cursor++;
		// Figure out the amount of pixels you typed
		int pixels = font->letters[(int)added].advancex;
		// Adjust the widths accordingly
		widthInPixels += pixels;
		totalWidth += pixels;
	}
		//~ cout << "Visible: " << widthInPixels << "/" << w << " Total Width: " << totalWidth << endl;
	
	// Check to see if there's no reason to scroll
	// What this says is 'if the amount of pixels you typed altogether doesn't
	// fill the chat-box'
	if ( totalWidth < widthWithoutBorder ) {
		// then set scroll to 0 and the width of pixels you're seeing to be
		// the width of the current string
		scroll = 0;
		widthInPixels = font->widthOfString( buffer );
	}
	
	// If you're only looking at less than half of a chatbar because you're scrolled
	// to the right, then scroll left. The 'totalWidth > w' is probably made superfluous
	// by the above 'if' statement
	while ( widthInPixels < widthWithoutBorder / 2 && totalWidth > widthWithoutBorder && scroll > 0 ) {
		// Just keep scrolling left one character at a time until
		// we're viewing at least half a chat-bar's worth of characters
		int pixels = font->letters[buffer[scroll-1]].advancex;
		widthInPixels += pixels;
		scroll--;
		//~ cout << "Scrolling left and adding " << pixels << " pixels " << endl;
	}
		
	// If you're viewing too many character, then keep scrolling right until you aren't
	while ( widthInPixels > widthWithoutBorder ) {
		widthInPixels -= font->letters[buffer[scroll]].advancex;
		scroll++;
	}
	
	// A bunch of bounds-checking stuff.
	// Cursor cannot be less than 0
	if ( cursor < 0 ) cursor = 0;
	// Cursor cannot be greater than the length of the string
	if ( cursor > buffer.length() ) cursor = buffer.length();
	// Cursor cannot be invisible
	if ( cursor < scroll ) {
		scroll = cursor;
	}
	// You cannot be scrolled before the string starts
	if ( scroll < 0 ) scroll = 0;
	
	//~ cout << "Scroll: " << scroll << " Cursor: " << cursor << endl;
}

void TextLine::keyUp(Event e) {
	
}

void TextLine::setSize( int newW, int newH ) {
	w = newW;
	int imageWidth, imageHeight;
	
	ImageHandler::getInstance()->getImageSize( imageWidth, imageHeight, sideID2 );
	widthWithoutBorder = w - 2 * imageWidth;
	
	h = newH;
}

